<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>下拉菜单（重新实现版）</title>
    <style>
        .box {
            width: 200px;
            height: 40px;
            line-height: 40px;
            margin: 50px auto;
        }

        .box span {
            display: block;
            height: 40px;
            border: solid 1px black;
        }

        .box ul {
            margin: 0;
            padding: 0;
            list-style: none;
            border: solid 1px black;
            border-top: none;
            display: none;
        }

        .box ul li {
            text-indent: 4px;
            display: flex;
        }

        .box ul li.hover {
            background: #66f;
            color: #fff;
        }

        .box ul li#active::after {
            content: "✅";
            margin-left: auto;
            margin-right: 20px;
        }
    </style>

</head>
<body>
    <div class="box">
        <span></span>
        <ul>
            <li>上海</li>
            <li>杭州</li>
            <li>南京</li>
            <li>苏州</li>
            <li>北京</li>
            <li>深圳</li>
            <li>广州</li>
        </ul>
    </div>
</body>
<script>

    let span = document.querySelector(".box span")
    let oul = document.querySelector(".box ul")
    let ali = oul.children;

    // 全局变量
    let flag = {
        currentIndex: -1,
    };

    /**      为操作事件添加监听方法         **/

    // 为 li 绑定事件
    for (let i = 0; i < ali.length; i++) {
        ali[i].addEventListener("mouseover", highlight)
        ali[i].addEventListener("mouseout", clearHighlight)
        ali[i].addEventListener("click", changeInitText)
    }
    span.innerHTML = ali[flag.currentIndex + 1].innerHTML;
    document.addEventListener("keydown", selectWithUpOrDownKey)

    // 出现了事件冒泡 bug TODO 思考：是谁在冒泡
    span.addEventListener("click", displayOrHiddenList);
    document.addEventListener("click", hiddenList)

    /**      方法的具体实现         **/
    function hiddenList() {
        if (oul.style.display === "block") {
            oul.style.display = "none";
        }
    }

    function changeInitText() {
        clearAllActive()
        this.id = "active";
        span.innerHTML = this.innerHTML;
    }

    function clearAllActive(){
        for (let i = 0; i < ali.length; i++) {
            ali[i].id = ""
        }
    }

    function clearHighlight() {
        this.className = "";
        flag.currentIndex = 0
    }

    function clearAllHighlight() {
        for (let i = 0; i < ali.length; i++) {
            ali[i].className = ""
        }
    }

    function highlight() {
        clearAllHighlight()
        this.className = "hover";
    }


    function selectWithUpOrDownKey(eve) {
        let e = eve || window.event
        let code = e.keyCode || e.which;
        highlightWithKey(code)
    }

    function initCurrentIndex() {
        for (let i = 0; i < ali.length; i++) {
            if (ali[i].className === "hover") {
                flag.currentIndex = i;
            }
        }
    }

    function highlightWithKey(code) {
        // console.log(flag.currentIndex)
        // 如果鼠标没开始 默认
        // 如果鼠标先开始 就得获取 className 为 hover 的 li 下标 开始
        initCurrentIndex();

        if (code === 40 && flag.currentIndex < ali.length - 1) {
            flag.currentIndex += 1
            ali[flag.currentIndex].className = "hover"
            if (ali[flag.currentIndex - 1]){
                ali[flag.currentIndex - 1].className = "";
            }
        }

        if (code === 38 && flag.currentIndex > 0) {
            flag.currentIndex -= 1
            ali[flag.currentIndex].className = "hover"
            ali[flag.currentIndex + 1].className = ""
        }
    }


    function displayOrHiddenList(eve) {
        let e = eve || window.event
        e.stopPropagation();
        if (oul.style.display === "block") {
            oul.style.display = "none";
        } else {
            oul.style.display = "block";
        }
    }

</script>
</html>